package com.dap.param;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.dap.aop.ValidationAop;
import com.dap.exception.IllegalArgumentException;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * 业务数据为JSON/XML/TEXT的入参
 */
public class StringInput extends BaseInput {
    private static final long serialVersionUID = 6557022983895081649L;
    private static final Logger logger = LoggerFactory.getLogger(StringInput.class);
    private static final ValidationAop validation = new ValidationAop();

    /**
     * JSON/XML/TEXT
     */
    private String body;


    @Override
    public String toString() {
        return ctrlData.toString() + ":" + body;
    }


    public StringInput() {
        super();
    }

    public StringInput(ControlData ctrlData) {
        super(ctrlData);
    }
    public StringInput(ControlData ctrlData, String bodyString) {
        super(ctrlData);
        this.body = bodyString;
    }
    public StringInput(ControlData ctrlData, Object bodyObject) {
        super(ctrlData);
        this.body = JSON.toJSONString(bodyObject);
    }


    public StringInput(String str) {
        super();
        this.body = str;
    }

    public StringInput(Object obj) {
        super();
        this.body = JSON.toJSONString(obj);
    }

    public static StringInput generateStringInputWithDateFormat(Object obj) {
        StringInput stringInput = new StringInput();
        stringInput.body = JSON.toJSONStringWithDateFormat(obj, "yyyy-MM-dd HH:mm:ss.SSS", SerializerFeature.WriteDateUseDateFormat);
        return stringInput;
    }



    public String getBody() {
        return body;
    }
    public void setBody(String body) {
        this.body = body;
    }


    public <T> T parseObject(Class<T> clazz) {
        return parseObjectInternal(body, clazz);
    }
    public <T> List<T> parseObjectList(Class<T> clazz) {
        return parseObjectListInternal(body, clazz);
    }

    public <T> T parseObject(Class<T> clazz, boolean treatEmptyStringAsNull) {
        String body = this.body;
        if (treatEmptyStringAsNull)
            body = convertEmptyStringToNull(body);

        return parseObjectInternal(body, clazz);
    }
    public <T> List<T> parseObjectList(Class<T> clazz, boolean treatEmptyStringAsNull) {
        String body = this.body;
        if (treatEmptyStringAsNull)
            body = convertEmptyStringToNull(body);

        return parseObjectListInternal(body, clazz);
    }


    private static <T> T parseObjectInternal(String body, Class<T> clazz) {
        T t = JSON.parseObject(body, clazz);
        if (t == null) {
            try {
                t = clazz.newInstance();
            } catch (InstantiationException e) {
                logger.info("body = " + body, e);
            } catch (IllegalAccessException e) {
                logger.info("body = " + body, e);
            }
        } else {
            try {
                validation.validate(t);
            } catch (IllegalArgumentException e) {
                logger.debug("body = {}", body);
                throw e;
            }
        }
        return t;
    }
    private static <T> List<T> parseObjectListInternal(String body, Class<T> clazz) {
        List<T> t = JSON.parseArray(body, clazz);
        if (t == null) {
            t = Lists.newArrayList();
        } else {
            try {
                validation.validate(t.toArray());
            } catch (IllegalArgumentException e) {
                logger.debug("body = {}", body);
                throw e;
            }
        }
        return t;
    }

    private static String convertEmptyStringToNull(String body) {
        if (StringUtils.isEmpty(body)) {
            return "";
        }

        StringBuilder sb = new StringBuilder();

        final int lastIdx = body.length() - 1;
        int i = 0;
        while (i < lastIdx) {
            if ('"' == body.charAt(i)) {
                if ('"' == body.charAt(i+1)) {
                    sb.append("null");
                } else {
                    sb.append(body.charAt(i)).append(body.charAt(i+1));
                }

                i += 2;
            } else {
                sb.append(body.charAt(i));
                ++i;
            }
        }
        if (i == lastIdx) {
            sb.append(body.charAt(i));
        }

        return sb.toString();
    }

}
